package com.andy.blog.common.utils;

import com.andy.blog.common.exception.UtilsException;
import com.google.common.collect.Lists;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * JavaBean 转换工具类
 * Created by andy on 2022-04-09 12:10
 */
public class TransformUtils {

    private TransformUtils() {
    }

    private static final Logger logger = LoggerFactory.getLogger(TransformUtils.class);

    private static final String WHERE = TransformUtils.class.getSimpleName();

    /**
     * 创建一个目标类型的实例并把source对象的值设置到目标对象中
     *
     * @param source 源对象
     * @param clazz  目标对象的类型
     * @return 返回目标对象
     */
    public static <D, E> E transform(D source, Class<E> clazz) {
        if (source == null) {
            return null;
        }

        return new DozerBeanMapper().map(source, clazz);
    }

    /**
     * 把源集合数据转换成目标类型的集合数据
     *
     * @param sourceList 源集合数据
     * @param clazz  目标集合元素的类型
     * @return 返回新的集合
     */
    public static <D, E> List<E> transformList(List<D> sourceList, Class<E> clazz) {
        if (sourceList == null) {
            return Collections.emptyList();
        }
        DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();

        List<E> destinationList = Lists.newArrayListWithCapacity(sourceList.size());
        for (D d : sourceList) {
            destinationList.add(dozerBeanMapper.map(d, clazz));
        }
        return destinationList;
    }

    /**
     * 使用java内省机制将javabean转Map
     *
     * @param bean bean对象
     * @return map
     */
    public static Map<String, Object> transBean2Map(Object bean) throws UtilsException {

        if (Objects.isNull(bean)) {
            return Collections.emptyMap();
        }

        Map<String, Object> map = new HashMap<>();
        try {
            // 获取javabean的描述器
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
            // 获取属性描述器
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            for (PropertyDescriptor descriptor : propertyDescriptors) {
                Object value = descriptor.getReadMethod().invoke(bean);
                map.put(descriptor.getName(), value);
            }
        } catch (Exception e) {
            logger.error("[{}].bean转map失败", WHERE);
            throw new UtilsException("bean转map失败");
        }

        return map;
    }


    /**
     * 使用java内省机制将Map转为javabean
     *
     * @param map   源map
     * @param clazz 被转对象
     * @param <T>   T
     * @return T
     */
    public static <T> T transMap2Bean(Map<String, Object> map, Class<T> clazz) throws UtilsException {

        if (Objects.isNull(map)) {
            return null;
        }

        T obj;
        try {
            obj = clazz.newInstance();

            // 获取javabean的描述器
            BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class);
            // 获取属性描述器
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor descriptor : propertyDescriptors) {
                String name = descriptor.getName();
                descriptor.getWriteMethod().invoke(obj, map.get(name));
            }
        } catch (Exception e) {
            logger.error("[{}].map转bean失败", WHERE);
            throw new UtilsException("map转bean失败");
        }

        return obj;
    }
}
